﻿using Microsoft.Win32;
using MvCamCtrl.NET;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using VM.PlatformSDKCS;

namespace CarPCBATest.Procedure
{
    internal class CameraTool
    {
        private static bool open = false;
        private static bool getImage = false;
        private static MyCamera.cbOutputExdelegate ImageCallback;
        public static MyCamera m_MyCamera = new MyCamera();
        private static List<ImageBaseData> imageBaseDatas = new List<ImageBaseData>();

        private static MyCamera.MV_GENTL_DEV_INFO_LIST m_stDeviceList = new MyCamera.MV_GENTL_DEV_INFO_LIST();
        private static MyCamera.MV_GENTL_IF_INFO_LIST m_stIFInfoList = new MyCamera.MV_GENTL_IF_INFO_LIST();

        public static void Open()
        {
            int nRet = MyCamera.MV_CC_EnumInterfacesByGenTL_NET(ref m_stIFInfoList, "C:\\Program Files (x86)\\Common Files\\MVS\\Runtime\\Win64_x64\\MvFGProducerCML.cti");

                                                                       //string s = "C:\\Program Files (x86)\\Common Files\\MVS\\Runtime\\Win64_x64";

            for (UInt32 i = 0; i < m_stIFInfoList.nInterfaceNum; i++)
            {
                MyCamera.MV_GENTL_IF_INFO stIFInfo = (MyCamera.MV_GENTL_IF_INFO)Marshal.PtrToStructure(m_stIFInfoList.pIFInfo[i], typeof(MyCamera.MV_GENTL_IF_INFO));

                Console.Write("TLType:" + stIFInfo.chTLType + " " + stIFInfo.chInterfaceID + " " + stIFInfo.chDisplayName);
            }

            // ch:枚举设备 | en:Enum device
            Console.WriteLine("Enum device count : " + Convert.ToString(m_stIFInfoList.nInterfaceNum));
            if (1 != m_stIFInfoList.nInterfaceNum)
            {
                throw new Exception($"发现[{m_stIFInfoList.nInterfaceNum}]个相机");
            }

            //MyCamera.MV_CC_DEVICE_INFO stDevInfo;                            // 通用设备信息

            //// ch:打印设备信息 en:Print device info
            //for (Int32 i = 0; i < m_stIFInfoList.nInterfaceNum; i++)
            //{
            //    stDevInfo = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(m_stIFInfoList.pIFInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO));

            //    if (MyCamera.MV_GIGE_DEVICE == stDevInfo.nTLayerType)
            //    {
            //        MyCamera.MV_GIGE_DEVICE_INFO stGigEDeviceInfo = (MyCamera.MV_GIGE_DEVICE_INFO)MyCamera.ByteToStruct(stDevInfo.SpecialInfo.stGigEInfo, typeof(MyCamera.MV_GIGE_DEVICE_INFO));
            //        uint nIp1 = ((stGigEDeviceInfo.nCurrentIp & 0xff000000) >> 24);
            //        uint nIp2 = ((stGigEDeviceInfo.nCurrentIp & 0x00ff0000) >> 16);
            //        uint nIp3 = ((stGigEDeviceInfo.nCurrentIp & 0x0000ff00) >> 8);
            //        uint nIp4 = (stGigEDeviceInfo.nCurrentIp & 0x000000ff);
            //        Console.WriteLine("[device " + i.ToString() + "]:");
            //        Console.WriteLine("DevIP:" + nIp1 + "." + nIp2 + "." + nIp3 + "." + nIp4);
            //        Console.WriteLine("UserDefineName:" + stGigEDeviceInfo.chUserDefinedName + "\n");
            //    }
            //    else if (MyCamera.MV_USB_DEVICE == stDevInfo.nTLayerType)
            //    {
            //        MyCamera.MV_USB3_DEVICE_INFO stUsb3DeviceInfo = (MyCamera.MV_USB3_DEVICE_INFO)MyCamera.ByteToStruct(stDevInfo.SpecialInfo.stUsb3VInfo, typeof(MyCamera.MV_USB3_DEVICE_INFO));
            //        Console.WriteLine("[device " + i.ToString() + "]:");
            //        Console.WriteLine("SerialNumber:" + stUsb3DeviceInfo.chSerialNumber);
            //        Console.WriteLine("UserDefineName:" + stUsb3DeviceInfo.chUserDefinedName + "\n");
            //    }
            //}
            //Int32 nDevIndex = 0;

            // ch:创建设备列表 | en:Create Device List
            System.GC.Collect();
            m_stDeviceList.nDeviceNum = 0;

            MyCamera.MV_GENTL_IF_INFO stIFInfo2 = (MyCamera.MV_GENTL_IF_INFO)Marshal.PtrToStructure(m_stIFInfoList.pIFInfo[0],
                typeof(MyCamera.MV_GENTL_IF_INFO));

            nRet = MyCamera.MV_CC_EnumDevicesByGenTL_NET(ref stIFInfo2, ref m_stDeviceList);
            if (0 != nRet)
            {
                //ShowErrorMsg("Enumerate devices fail!", 0);
                return;
            }

            // ch:获取选择的设备信息 | en:Get selected device information
            MyCamera.MV_GENTL_DEV_INFO device = (MyCamera.MV_GENTL_DEV_INFO)Marshal.PtrToStructure(m_stDeviceList.pDeviceInfo[0], typeof(MyCamera.MV_GENTL_DEV_INFO));

            // ch:打开设备 | en:Open device
            if (null == m_MyCamera)
            {
                m_MyCamera = new MyCamera();
                if (null == m_MyCamera)
                {
                    return;
                }
            }

            int reslut = m_MyCamera.MV_CC_CreateDeviceByGenTL_NET(ref device);
            if (MyCamera.MV_OK != reslut)
            {
                return;
            }

            reslut = m_MyCamera.MV_CC_OpenDevice_NET();
            if (MyCamera.MV_OK != reslut)
            {
                m_MyCamera.MV_CC_DestroyDevice_NET();
                //ShowErrorMsg("Device open fail!", nRet);
                return;
            }

            // ch:设置触发模式为off || en:set trigger mode as off
            nRet = m_MyCamera.MV_CC_SetEnumValue_NET("TriggerMode", 0);
            if (MyCamera.MV_OK != nRet)
            {
                throw new Exception("Set TriggerMode failed");
            }

            // ch:注册回调函数 | en:Register image callback
            ImageCallback = new MyCamera.cbOutputExdelegate(ImageCallbackFunc);
            nRet = m_MyCamera.MV_CC_RegisterImageCallBackEx_NET(ImageCallback, IntPtr.Zero);
            if (MyCamera.MV_OK != nRet)
            {
                throw new Exception("Register image callback failed!");
            }
            open = true;
        }

        private static void ImageCallbackFunc(IntPtr pData, ref MyCamera.MV_FRAME_OUT_INFO_EX pFrameInfo, IntPtr pUser)
        {
            Console.WriteLine("Get one frame: Width[" + Convert.ToString(pFrameInfo.nWidth) + "] , Height[" + Convert.ToString(pFrameInfo.nHeight)
                                + "] , FrameNum[" + Convert.ToString(pFrameInfo.nFrameNum) + "]" + "addr" + pData);

            imageBaseDatas.Add(CCDToImageBaseData(pData, pFrameInfo));
            getImage = true;
        }

        public static void Close()
        {
            if (!open)
            {
                return;
            }
            // ch:关闭设备 | en:Close device
            int nRet = m_MyCamera.MV_CC_CloseDevice_NET();
            if (MyCamera.MV_OK != nRet)
            {
                throw new Exception("Close device failed");
            }

            //// ch:销毁设备 | en:Destroy device
            nRet = m_MyCamera.MV_CC_DestroyDevice_NET();
            if (MyCamera.MV_OK != nRet)
            {
                throw new Exception("Destroy device failed");
            }
            open = false;
        }

        /// <summary>
        /// 获取
        /// </summary>
        /// <param name="elapsedMilliseconds"> </param>
        /// <returns> </returns>
        public static List<ImageBaseData> GetLatestImages()
        {
            return imageBaseDatas;
        }

        public static void StartGrab()
        {
            imageBaseDatas.Clear();
            // ch:开启抓图 || en: start grab image
            int nRet = m_MyCamera.MV_CC_StartGrabbing_NET();
            if (MyCamera.MV_OK != nRet)
            {
                throw new Exception("Start grabbing failed:{0:x8}");
            }
        }

        public static ImageBaseData GetCurrentImage()
        {
            //ExposureTime = 5000;
            imageBaseDatas.Clear();
            getImage = false;
            StartGrab();
            bool timeOut = false;
            Task.Run(() =>
            {
                Thread.Sleep(2000);
                timeOut = true;
            });
            while (!getImage)
            {
                if (timeOut)
                    break;
            }

            StopGrab();
            if (timeOut)
            {
                throw new Exception("采图执行异常0");
            }
            if (imageBaseDatas.Count < 1)
            {
                throw new Exception("采图执行异常1");
            }
            return imageBaseDatas[0];
        }

        public static void StopGrab()
        {
            // ch:停止抓图 | en:Stop grabbing
            int nRet = m_MyCamera.MV_CC_StopGrabbing_NET();
            if (MyCamera.MV_OK != nRet)
            {
                throw new Exception("Stop grabbing failed");
            }
        }

        private static ImageBaseData CCDToImageBaseData(IntPtr pdata, MyCamera.MV_FRAME_OUT_INFO_EX frame)
        {
            ImageBaseData imageBaseData = new ImageBaseData();
            imageBaseData.Width = frame.nWidth;
            imageBaseData.Height = frame.nHeight;
            imageBaseData.DataLen = frame.nFrameLen;
            //PixelType_Gvsp_BayerRG8 = 17301513,
            imageBaseData.Pixelformat = (int)VMPixelFormat.VM_PIXEL_RGB24_C3;
            //if (frame.enPixelType == MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG8)
            //{
            //    imageBaseData.Pixelformat = (int)VMPixelFormat.VM_PIXEL_MONO_08;
            //}
            //else if (frame.enPixelType == MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed)
            //{
            //    imageBaseData.Pixelformat = (int)VMPixelFormat.VM_PIXEL_RGB24_C3;
            //}
            //else
            //{
            //    imageBaseData.Pixelformat = (int)VMPixelFormat.VM_PIXEL_RGB24_C3;
            //}
            imageBaseData.ImageData = new byte[frame.nFrameLen];
            Marshal.Copy(pdata, imageBaseData.ImageData, 0, (int)frame.nFrameLen);
            return imageBaseData;
        }
    }
}